﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YJKCodeBase.WinForm;
using YJKView;

namespace DoorAndWindow
{
	[Regeneration(RegenerationOption.Manual)]
	[Transaction(TransactionMode.Manual)]
	public class CmdTopBottomDim : YJKCommandManual
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		protected override Result YJKExcute(ExternalCommandData cmdData, ref string message, ElementSet elements)
		{
			CmdViewType types = CmdViewType.Elevation;
			if (SwitchView.SetUsableView(types, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			if (CmdTopBottomDim._hWndRevit == null)
			{
				Process currentProcess = Process.GetCurrentProcess();
				IntPtr mainWindowHandle = currentProcess.MainWindowHandle;
				CmdTopBottomDim._hWndRevit = new WindowHandle(mainWindowHandle);
			}
			DlgTopBottomDim instance = DlgTopBottomDim.GetInstance(cmdData);
			instance.Show(CmdTopBottomDim._hWndRevit);
			int wMsg = 7;
			CmdTopBottomDim.SendMessage(CmdTopBottomDim._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Document document = cmdData.Application.ActiveUIDocument.Document;
			Transaction transaction = new Transaction(document, "门窗标高");
			try
			{
				bool flag = true;
				for (;;)
				{
					transaction.Start();
					if (instance.mode == 0)
					{
						flag = this.CreateSingle(instance);
					}
					else if (1 == instance.mode)
					{
						flag = this.CreateRect(instance);
					}
					transaction.Commit();
					if (!flag)
					{
						if (!instance.clickModeBtn)
						{
							break;
						}
						instance.clickModeBtn = false;
					}
				}
			}
			catch (Exception)
			{
				transaction.RollBack();
				instance.Close();
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			instance.Close();
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public bool CreateSingle(DlgTopBottomDim dlg)
		{
			try
			{
				View activeView = this.m_doc.ActiveView;
				DoorWinFilter doorWinFilter = new DoorWinFilter();
				Element element = this.m_doc.GetElement(this.m_uiApp.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, doorWinFilter, "请选择需要标记的门窗"));
				FamilyInstance e = element as FamilyInstance;
				if (dlg.TopDim)
				{
					List<Reference> list = this.FindTopMostReference(e);
					foreach (Reference reference in list)
					{
						XYZ globalPoint = reference.GlobalPoint;
						try
						{
							SpotDimension spotDimension = this.m_doc.Create.NewSpotElevation(activeView, reference, globalPoint, globalPoint, globalPoint, globalPoint, true);
							spotDimension.DimensionType = dlg.SpotDimensionType;
							break;
						}
						catch
						{
						}
					}
				}
				if (dlg.BottomDim)
				{
					List<Reference> list2 = this.FindBottomMostReference(e);
					foreach (Reference reference2 in list2)
					{
						XYZ globalPoint2 = reference2.GlobalPoint;
						try
						{
							SpotDimension spotDimension2 = this.m_doc.Create.NewSpotElevation(activeView, reference2, globalPoint2, globalPoint2, globalPoint2, globalPoint2, true);
							spotDimension2.DimensionType = dlg.SpotDimensionType;
							break;
						}
						catch
						{
						}
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		public bool CreateRect(DlgTopBottomDim dlg)
		{
			try
			{
				View activeView = this.m_doc.ActiveView;
				DoorWinFilter doorWinFilter = new DoorWinFilter();
				IList<Reference> list = this.m_uiDoc.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, doorWinFilter, "请选择需要标记的门窗");
				foreach (Reference reference in list)
				{
					FamilyInstance e = this.m_doc.GetElement(reference) as FamilyInstance;
					if (dlg.TopDim)
					{
						List<Reference> list2 = this.FindTopMostReference(e);
						foreach (Reference reference2 in list2)
						{
							XYZ globalPoint = reference2.GlobalPoint;
							try
							{
								SpotDimension spotDimension = this.m_doc.Create.NewSpotElevation(activeView, reference2, globalPoint, globalPoint, globalPoint, globalPoint, true);
								spotDimension.DimensionType = dlg.SpotDimensionType;
							}
							catch
							{
							}
						}
					}
					if (dlg.BottomDim)
					{
						List<Reference> list3 = this.FindBottomMostReference(e);
						foreach (Reference reference3 in list3)
						{
							XYZ globalPoint2 = reference3.GlobalPoint;
							try
							{
								SpotDimension spotDimension2 = this.m_doc.Create.NewSpotElevation(activeView, reference3, globalPoint2, globalPoint2, globalPoint2, globalPoint2, true);
								spotDimension2.DimensionType = dlg.SpotDimensionType;
								break;
							}
							catch
							{
							}
						}
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private List<Reference> FindTopMostReference(FamilyInstance e)
		{
			ElementId elementId = e.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).AsElementId();
			Level level = this.m_doc.GetElement(elementId) as Level;
			double elevation = level.Elevation;
			e.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).AsDouble();
			double val = e.get_Parameter(BuiltInParameter.INSTANCE_HEAD_HEIGHT_PARAM).AsDouble() + elevation;
			Document document = e.Document;
			SubTransaction subTransaction = new SubTransaction(document);
			subTransaction.Start();
			XYZ pDirection = new XYZ(0.0, 0.0, -1.0);
			View3D view3D = RevitVersionFuncs.NewView3D(document, XYZ.BasisZ);
            view3D.DetailLevel = (ViewDetailLevel)3;
			BoundingBoxXYZ boundingBoxXYZ = e.get_BoundingBox(view3D);
			Wall wall = e.Host as Wall;
			XYZ max = boundingBoxXYZ.Max;
			XYZ xyz = boundingBoxXYZ.Min;
			xyz = new XYZ(xyz.X, xyz.Y, max.Z);
			XYZ xyz2 = xyz.Add(max).Divide(2.0);
			XYZ xyz3 = new XYZ(xyz2.X, xyz2.Y, xyz2.Z + 1.0);
			xyz3 -= wall.Orientation.Normalize().Multiply(wall.Width / 2.0);
			List<XYZ> list = new List<XYZ>();
			for (int i = 0; i < 3; i++)
			{
				list.Add(xyz3 + wall.Orientation.Normalize().Multiply(wall.Width * (double)i / 2.0));
			}
			LocationPoint locationPoint = e.Location as LocationPoint;
			XYZ xyz4 = new XYZ(locationPoint.Point.X, locationPoint.Point.Y, max.Z + 1.0);
			xyz4 -= wall.Orientation.Normalize().Multiply(wall.Width / 2.0);
			for (int j = 0; j < 3; j++)
			{
				list.Add(xyz4 + wall.Orientation.Normalize().Multiply(wall.Width * (double)j / 2.0));
			}
			List<ReferenceWithContext> list2 = new List<ReferenceWithContext>();
			foreach (XYZ pOrigin in list)
			{
				IList<ReferenceWithContext> list3 = RevitVersionFuncs.FindReferencesWithContextByDirection(document, pOrigin, pDirection, view3D);
				foreach (ReferenceWithContext item in list3)
				{
					if (!list2.Contains(item))
					{
						list2.Add(item);
					}
				}
			}
			List<Reference> list4 = new List<Reference>();
			foreach (ReferenceWithContext referenceWithContext in list2)
			{
				Reference reference = referenceWithContext.GetReference();
				double d = AssistFunc.feetToMM(val);
				double d2 = AssistFunc.feetToMM(reference.GlobalPoint.Z);
				if (GeoUtil.IsEqual(d, d2))
				{
					list4.Add(reference);
				}
			}
			subTransaction.RollBack();
			return list4;
		}

		private List<Reference> FindBottomMostReference(FamilyInstance e)
		{
			ElementId elementId = e.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).AsElementId();
			Level level = this.m_doc.GetElement(elementId) as Level;
			double elevation = level.Elevation;
			double val = e.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).AsDouble() + elevation;
			e.get_Parameter(BuiltInParameter.INSTANCE_HEAD_HEIGHT_PARAM).AsDouble();
			Document document = e.Document;
			SubTransaction subTransaction = new SubTransaction(document);
			subTransaction.Start();
			XYZ pDirection = new XYZ(0.0, 0.0, 1.0);
			View3D view3D = RevitVersionFuncs.NewView3D(document, XYZ.BasisZ);
            view3D.DetailLevel = (ViewDetailLevel)3;
			BoundingBoxXYZ boundingBoxXYZ = e.get_BoundingBox(view3D);
			Wall wall = e.Host as Wall;
			XYZ min = boundingBoxXYZ.Min;
			XYZ xyz = boundingBoxXYZ.Max;
			xyz = new XYZ(xyz.X, xyz.Y, min.Z);
			XYZ xyz2 = xyz.Add(min).Divide(2.0);
			XYZ xyz3 = new XYZ(xyz2.X, xyz2.Y, xyz2.Z - 1.0);
			xyz3 -= wall.Orientation.Normalize().Multiply(wall.Width / 2.0);
			List<XYZ> list = new List<XYZ>();
			for (int i = 0; i < 3; i++)
			{
				list.Add(xyz3 + wall.Orientation.Normalize().Multiply(wall.Width * (double)i / 2.0));
			}
			LocationPoint locationPoint = e.Location as LocationPoint;
			XYZ xyz4 = new XYZ(locationPoint.Point.X, locationPoint.Point.Y, min.Z - 1.0);
			xyz4 -= wall.Orientation.Normalize().Multiply(wall.Width / 2.0);
			for (int j = 0; j < 3; j++)
			{
				list.Add(xyz4 + wall.Orientation.Normalize().Multiply(wall.Width * (double)j / 2.0));
			}
			List<ReferenceWithContext> list2 = new List<ReferenceWithContext>();
			foreach (XYZ pOrigin in list)
			{
				IList<ReferenceWithContext> list3 = RevitVersionFuncs.FindReferencesWithContextByDirection(document, pOrigin, pDirection, view3D);
				foreach (ReferenceWithContext item in list3)
				{
					if (!list2.Contains(item))
					{
						list2.Add(item);
					}
				}
			}
			List<Reference> list4 = new List<Reference>();
			foreach (ReferenceWithContext referenceWithContext in list2)
			{
				Reference reference = referenceWithContext.GetReference();
				double d = AssistFunc.feetToMM(val);
				double d2 = AssistFunc.feetToMM(reference.GlobalPoint.Z);
				if (GeoUtil.IsEqual(d, d2))
				{
					list4.Add(reference);
				}
			}
			subTransaction.RollBack();
			return list4;
		}

		public static WindowHandle _hWndRevit;
	}
}
